#ifndef __RTMP_H__
#define __RTMP_H__
/*
 *      Copyright (C) 2005-2008 Team XBMC
 *      http://www.xbmc.org
 *      Copyright (C) 2008-2009 Andrej Stepanchuk
 *      Copyright (C) 2009-2010 Howard Chu
 *
 *  This file is part of librtmp.
 *
 *  librtmp is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1,
 *  or (at your option) any later version.
 *
 *  librtmp is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with librtmp see the file COPYING.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA  02110-1301, USA.
 *  http://www.gnu.org/copyleft/lgpl.html
 */

#if !defined(NO_CRYPTO) && !defined(CRYPTO)
#define CRYPTO
#else
#include <sys/types.h> //for off_t
#endif

#include <errno.h>
#include <stdint.h>

#ifdef _WIN32
#ifdef _MSC_VER
#pragma warning(disable:4996) //depricated warnings
#pragma warning(disable:4244) //64bit defensive mechanism, fixed the ones that mattered
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#define SOCKET int
#endif

#include "amf.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define RTMP_LIB_VERSION	0x020300	/* 2.3 */

#define RTMP_FEATURE_HTTP	0x01
#define RTMP_FEATURE_ENC	0x02
#define RTMP_FEATURE_SSL	0x04
#define RTMP_FEATURE_MFP	0x08	/* not yet supported */
#define RTMP_FEATURE_WRITE	0x10	/* publish, not play */
#define RTMP_FEATURE_HTTP2	0x20	/* server-side rtmpt */

#define RTMP_PROTOCOL_UNDEFINED	-1
#define RTMP_PROTOCOL_RTMP      0
#define RTMP_PROTOCOL_RTMPE     RTMP_FEATURE_ENC
#define RTMP_PROTOCOL_RTMPT     RTMP_FEATURE_HTTP
#define RTMP_PROTOCOL_RTMPS     RTMP_FEATURE_SSL
#define RTMP_PROTOCOL_RTMPTE    (RTMP_FEATURE_HTTP|RTMP_FEATURE_ENC)
#define RTMP_PROTOCOL_RTMPTS    (RTMP_FEATURE_HTTP|RTMP_FEATURE_SSL)
#define RTMP_PROTOCOL_RTMFP     RTMP_FEATURE_MFP

#define RTMP_DEFAULT_CHUNKSIZE	128

	/* needs to fit largest number of bytes recv() may return */
#define RTMP_BUFFER_CACHE_SIZE (16*1024)

#define	RTMP_CHANNELS	65600

	extern const char RTMPProtocolStringsLower[][7];
	extern const AVal RTMP_DefaultFlashVer;
	extern int RTMP_ctrlC;

	/*      RTMP_PACKET_TYPE_...                0x00 */
#define RTMP_PACKET_TYPE_CHUNK_SIZE         0x01
	/*      RTMP_PACKET_TYPE_...                0x02 */
#define RTMP_PACKET_TYPE_BYTES_READ_REPORT  0x03
#define RTMP_PACKET_TYPE_CONTROL            0x04
#define RTMP_PACKET_TYPE_SERVER_BW          0x05
#define RTMP_PACKET_TYPE_CLIENT_BW          0x06
	/*      RTMP_PACKET_TYPE_...                0x07 */
#define RTMP_PACKET_TYPE_AUDIO              0x08
#define RTMP_PACKET_TYPE_VIDEO              0x09
	/*      RTMP_PACKET_TYPE_...                0x0A */
	/*      RTMP_PACKET_TYPE_...                0x0B */
	/*      RTMP_PACKET_TYPE_...                0x0C */
	/*      RTMP_PACKET_TYPE_...                0x0D */
	/*      RTMP_PACKET_TYPE_...                0x0E */
#define RTMP_PACKET_TYPE_FLEX_STREAM_SEND   0x0F
#define RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT 0x10
#define RTMP_PACKET_TYPE_FLEX_MESSAGE       0x11
#define RTMP_PACKET_TYPE_INFO               0x12
#define RTMP_PACKET_TYPE_SHARED_OBJECT      0x13
#define RTMP_PACKET_TYPE_INVOKE             0x14
	/*      RTMP_PACKET_TYPE_...                0x15 */
#define RTMP_PACKET_TYPE_FLASH_VIDEO        0x16

#define RTMP_MAX_HEADER_SIZE 18

#define RTMP_SCRIPT_CHANNELID	0x03
#define RTMP_AUDIO_CHANNELID    0x04
#define RTMP_VIDEO_CHANNELID    0x05

#define RTMP_PACKET_SIZE_LARGE    0
#define RTMP_PACKET_SIZE_MEDIUM   1
#define RTMP_PACKET_SIZE_SMALL    2
#define RTMP_PACKET_SIZE_MINIMUM  3

	typedef struct RTMPChunk
	{
		int c_headerSize;
		int c_chunkSize;
		char *c_chunk;
		char c_header[RTMP_MAX_HEADER_SIZE];
	} RTMPChunk;

	typedef struct RTMPPacket
	{
		uint8_t m_headerType;
		uint8_t m_packetType;
		uint8_t m_hasAbsTimestamp;	/* timestamp absolute or relative? */
		int m_nChannel;
		uint32_t m_nTimeStamp;	/* timestamp */
		int32_t m_nInfoField2;	/* last 4 bytes in a long header */
		uint32_t m_nBodySize;
		uint32_t m_nBytesRead;
		RTMPChunk *m_chunk;
		char *m_body;
	} RTMPPacket;

	typedef struct RTMPSockBuf
	{
		SOCKET sb_socket;
		int sb_size;		/* number of unprocessed bytes in buffer */
		char *sb_start;		/* pointer into sb_pBuffer of next byte to process */
		char sb_buf[RTMP_BUFFER_CACHE_SIZE];	/* data read from socket */
		int sb_timedout;
		void *sb_ssl;
	} RTMPSockBuf;

#define RTMPPacket_IsReady(a)	((a)->m_nBytesRead == (a)->m_nBodySize)

	typedef struct RTMP_Stream {
		int id;
		AVal playpath;
	} RTMP_Stream;

	typedef struct RTMP_LNK
	{
#define RTMP_MAX_STREAMS 8
		RTMP_Stream streams[RTMP_MAX_STREAMS];
		int nStreams;
		int curStreamIdx;
		int playingStreams;

		AVal hostname;
		AVal sockshost;

		AVal tcUrl;
		AVal swfUrl;
		AVal pageUrl;
		AVal app;
		AVal auth;
		AVal flashVer;
		AVal subscribepath;
		AVal usherToken;
		AVal token;
		AVal pubUser;
		AVal pubPasswd;
		AMFObject extras;
		int edepth;

		int seekTime;
		int stopTime;

#define RTMP_LF_AUTH	0x0001	/* using auth param */
#define RTMP_LF_LIVE	0x0002	/* stream is live */
#define RTMP_LF_SWFV	0x0004	/* do SWF verification */
#define RTMP_LF_PLST	0x0008	/* send playlist before play */
#define RTMP_LF_BUFX	0x0010	/* toggle stream on BufferEmpty msg */
#define RTMP_LF_FTCU	0x0020	/* free tcUrl on close */
		int lFlags;

		int swfAge;

		int protocol;
		int timeout;		/* connection timeout in seconds */

#define RTMP_PUB_NAME   0x0001  /* send login to server */
#define RTMP_PUB_RESP   0x0002  /* send salted password hash */
#define RTMP_PUB_ALLOC  0x0004  /* allocated data for new tcUrl & app */
#define RTMP_PUB_CLEAN  0x0008  /* need to free allocated data for newer tcUrl & app at exit */
#define RTMP_PUB_CLATE  0x0010  /* late clean tcUrl & app at exit */
		int pFlags;

		unsigned short socksport;
		unsigned short port;

#ifdef CRYPTO
#define RTMP_SWF_HASHLEN	32
		void *dh;			/* for encryption */
		void *rc4keyIn;
		void *rc4keyOut;

		uint32_t SWFSize;
		uint8_t SWFHash[RTMP_SWF_HASHLEN];
		char SWFVerificationResponse[RTMP_SWF_HASHLEN + 10];
#endif
	} RTMP_LNK;

	/* state for read() wrapper */
	typedef struct RTMP_READ
	{
		char *buf;
		char *bufpos;
		unsigned int buflen;
		uint32_t timestamp;
		uint8_t dataType;
		uint8_t flags;
#define RTMP_READ_HEADER	0x01
#define RTMP_READ_RESUME	0x02
#define RTMP_READ_NO_IGNORE	0x04
#define RTMP_READ_GOTKF		0x08
#define RTMP_READ_GOTFLVK	0x10
#define RTMP_READ_SEEKING	0x20
		int8_t status;
#define RTMP_READ_COMPLETE	-3
#define RTMP_READ_ERROR	-2
#define RTMP_READ_EOF	-1
#define RTMP_READ_IGNORE	0

		/* if bResume == TRUE */
		uint8_t initialFrameType;
		uint32_t nResumeTS;
		char *metaHeader;
		char *initialFrame;
		uint32_t nMetaHeaderSize;
		uint32_t nInitialFrameSize;
		uint32_t nIgnoredFrameCounter;
		uint32_t nIgnoredFlvFrameCounter;
	} RTMP_READ;

	typedef struct RTMP_METHOD
	{
		AVal name;
		int num;
	} RTMP_METHOD;

	typedef struct RTMP_BINDINFO
	{
		struct sockaddr_storage addr;
		int addrLen;
	} RTMP_BINDINFO;

	typedef int(*CUSTOMSEND)(RTMPSockBuf*, const char *, int, void*);

	typedef struct RTMP
	{
		int m_inChunkSize;
		int m_outChunkSize;
		int m_nBWCheckCounter;
		int m_nBytesIn;
		int m_nBytesInSent;
		int m_nBufferMS;
		int m_stream_id;		/* returned in _result from createStream */
		int m_mediaChannel;
		uint32_t m_mediaStamp;
		uint32_t m_pauseStamp;
		int m_pausing;
		int m_nServerBW;
		int m_nClientBW;
		uint8_t m_nClientBW2;
		uint8_t m_bPlaying;
		uint8_t m_bSendEncoding;
		uint8_t m_bSendCounter;

		uint8_t m_bUseNagle;
		uint8_t m_bCustomSend;
		void*   m_customSendParam;
		CUSTOMSEND m_customSendFunc;

		RTMP_BINDINFO m_bindIP;

		uint8_t m_bSendChunkSizeInfo;

		int m_numInvokes;
		int m_numCalls;
		RTMP_METHOD *m_methodCalls;	/* remote method calls queue */

		int m_channelsAllocatedIn;
		int m_channelsAllocatedOut;
		RTMPPacket **m_vecChannelsIn;
		RTMPPacket **m_vecChannelsOut;
		int *m_channelTimestamp;	/* abs timestamp of last packet */

		double m_fAudioCodecs;	/* audioCodecs for the connect packet */
		double m_fVideoCodecs;	/* videoCodecs for the connect packet */
		double m_fEncoding;		/* AMF0 or AMF3 */

		double m_fDuration;		/* duration of stream in seconds */

		int m_msgCounter;		/* RTMPT stuff */
		int m_polling;
		int m_resplen;
		int m_unackd;
		AVal m_clientID;

		RTMP_READ m_read;
		RTMPPacket m_write;
		RTMPSockBuf m_sb;
		RTMP_LNK Link;
		int connect_time_ms;
		int dns_time_ms;
		char hostIP[INET_ADDRSTRLEN];
		int last_error_code;
	} RTMP;

	DLL_EXPORT uint32_t RTMP_GetTime(void);
	DLL_EXPORT void RTMPPacket_Reset(RTMPPacket *p);
	DLL_EXPORT void RTMPPacket_Dump(RTMPPacket *p);
	DLL_EXPORT int RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize);
	DLL_EXPORT void RTMPPacket_Free(RTMPPacket *p);
	DLL_EXPORT int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, AVal *app);
	DLL_EXPORT void RTMP_ParsePlaypath(AVal *in, AVal *out);
	DLL_EXPORT void RTMP_SetBufferMS(RTMP *r, int size);
	DLL_EXPORT void RTMP_UpdateBufferMS(RTMP *r);
	DLL_EXPORT int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg);
	DLL_EXPORT int RTMP_SetupURL(RTMP *r, char *url);
	DLL_EXPORT int RTMP_AddStream(RTMP *r, const char *playpath);
	DLL_EXPORT void RTMP_SetupStream(RTMP *r, int protocol,
		AVal *hostname,
		unsigned int port,
		AVal *sockshost,
		AVal *playpath,
		AVal *tcUrl,
		AVal *swfUrl,
		AVal *pageUrl,
		AVal *app,
		AVal *auth,
		AVal *swfSHA256Hash,
		uint32_t swfSize,
		AVal *flashVer,
		AVal *subscribepath,
		AVal *usherToken,
		int dStart,
		int dStop, int bLiveStream, long int timeout);

	DLL_EXPORT int RTMP_Connect(RTMP *r, RTMPPacket *cp);
	struct sockaddr;
	DLL_EXPORT int RTMP_Connect0(RTMP *r, struct sockaddr *svc, socklen_t addrlen);
	DLL_EXPORT int RTMP_Connect1(RTMP *r, RTMPPacket *cp);
	DLL_EXPORT int RTMP_Serve(RTMP *r);
	DLL_EXPORT int RTMP_TLS_Accept(RTMP *r, void *ctx);

	DLL_EXPORT int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet);
	DLL_EXPORT int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue);
	DLL_EXPORT int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk);
	DLL_EXPORT int RTMP_IsConnected(RTMP *r);
	DLL_EXPORT SOCKET RTMP_Socket(RTMP *r);
	DLL_EXPORT int RTMP_IsTimedout(RTMP *r);
	DLL_EXPORT double RTMP_GetDuration(RTMP *r);
	DLL_EXPORT int RTMP_ToggleStream(RTMP *r);

	DLL_EXPORT int RTMP_ConnectStream(RTMP *r, int seekTime);
	DLL_EXPORT int RTMP_ReconnectStream(RTMP *r, int seekTime, int streamIdx);
	DLL_EXPORT void RTMP_DeleteStream(RTMP *r, int streamIdx);
	DLL_EXPORT int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet);
	DLL_EXPORT int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet);

	DLL_EXPORT void RTMP_Init(RTMP *r);
	DLL_EXPORT void RTMP_Reset(RTMP *r);
	DLL_EXPORT void RTMP_Close(RTMP *r);
	DLL_EXPORT RTMP *RTMP_Alloc(void);
	DLL_EXPORT void RTMP_TLS_Free();
	DLL_EXPORT void RTMP_Free(RTMP *r);
	DLL_EXPORT void RTMP_EnableWrite(RTMP *r);

	DLL_EXPORT void *RTMP_TLS_AllocServerContext(const char* cert, const char* key);
	DLL_EXPORT void RTMP_TLS_FreeServerContext(void *ctx);

	DLL_EXPORT int RTMP_LibVersion(void);
	DLL_EXPORT void RTMP_UserInterrupt(void);	/* user typed Ctrl-C */

	DLL_EXPORT int RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime);
	DLL_EXPORT int RTMP_SendPause(RTMP *r, int DoPause, int dTime);
	DLL_EXPORT int RTMP_Pause(RTMP *r, int DoPause);
	DLL_EXPORT int RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, AMFObjectProperty * p);

	DLL_EXPORT int RTMPSockBuf_Fill(RTMPSockBuf *sb);
	DLL_EXPORT int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len);
	DLL_EXPORT int RTMPSockBuf_Close(RTMPSockBuf *sb);

	DLL_EXPORT int RTMP_SendCreateStream(RTMP *r);
	DLL_EXPORT int RTMP_SendSeek(RTMP *r, int dTime);
	DLL_EXPORT int RTMP_SendServerBW(RTMP *r);
	DLL_EXPORT int RTMP_SendClientBW(RTMP *r);
	DLL_EXPORT void RTMP_DropRequest(RTMP *r, int i, int freeit);
	DLL_EXPORT int RTMP_Read(RTMP *r, char *buf, int size);
	DLL_EXPORT int RTMP_Write(RTMP *r, const char *buf, int size, int streamIdx, int channel);

	/* hashswf.c */
	DLL_EXPORT int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age);

#ifdef __cplusplus
};
#endif

#endif
